package gwtgaetools.shared.model;

import gwtgaetools.client.BasicList;
import gwtgaetools.client.ItemManager;
import gwtgaetools.client.listeners.DeleteListener;
import gwtgaetools.client.ui.IsListable;

import java.util.ArrayList;

public abstract class ObjectManager<T extends BaseObject<T, PE>, TT extends ObjectManager<T, TT, PE>, PE extends PropertyEnum<PE, T>> implements IsListable,
	DeleteListener<TT> {

	public ArrayList<DeleteListener<TT>>	deleteListeners	= new ArrayList<DeleteListener<TT>>();
	public TT								om;

	public ArrayList<ItemManager<String>> keys() {
		ArrayList<ItemManager<String>> out = new ArrayList<ItemManager<String>>();
		out.add(id);
		if (parent() != null)
			out.addAll(parent().keys());
		return out;
	}

	public ArrayList<ItemManager<?>>	properties	= new ArrayList<ItemManager<?>>();
	public BasicList<PE>				pIndices	= new BasicList<PE>();

	// public ArrayList<OMList<T extends Ba>> lists() { return new
	// ArrayList<OMList<?>>(); }

	public ItemManager<Integer> index() {
		return null;
	}

	public ItemManager<String>	id	= new ItemManager<String>();

	@SuppressWarnings("unchecked") public ObjectManager() {
		om = (TT) this;
	}

	public ObjectManager(T t) {
		this();
		setItem(t);
	}

	public void setItem(T t) {
		id.setItem(t.getId());

		for (PE pe : t.propNames()) {
			switch (pe.type()) {
			case BOOLEAN:
				properties.add(new ItemManager<Boolean>(t.getBoolean(pe)));
				break;
			case FLOAT:
				properties.add(new ItemManager<Float>(t.getFloat(pe)));
				break;
			case INTEGER:
				properties.add(new ItemManager<Integer>(t.getInteger(pe)));
				break;
			case STRING:
				properties.add(new ItemManager<String>(t.getProperty(pe)));
				break;
			default:
				break;

			}
		}
	}

	public ObjectManager(TT b) {
		this();
		setObservedManager(b);
		b.deleteListeners.add(this);
	}

	@SuppressWarnings("unchecked") public ItemManager<Boolean> getBoolean(int i) {
		return (ItemManager<Boolean>) properties.get(i);
	}

	@SuppressWarnings("unchecked") public ItemManager<Float> getFloat(int i) {
		return (ItemManager<Float>) properties.get(i);
	}

	@SuppressWarnings("unchecked") public ItemManager<Integer> getInt(int i) {
		return (ItemManager<Integer>) properties.get(i);
	}

	@SuppressWarnings("unchecked") public ItemManager<String> getString(int i) {
		return (ItemManager<String>) properties.get(i);
	}

	public ItemManager<Boolean> getBoolean(PE i) {
		return getBoolean(i.index());
	}

	public ItemManager<Float> getFloat(PE i) {
		return getFloat(i.index());
	}

	public ItemManager<Integer> getInt(PE i) {
		return getInt(i.index());
	}

	public ItemManager<String> getString(PE i) {
		return getString(i.index());
	}

	public void setBoolean(PE i, String s) {
		setBoolean(i.index(), Boolean.parseBoolean(s));
	}

	public void setFloat(PE i, String f) {
		setFloat(i.index(), Float.parseFloat(f));
	}

	public void setInt(PE i, String f) {
		setInt(i.index(), Integer.parseInt(f));
	}

	public void setBoolean(PE i, Boolean s) {
		setBoolean(i.index(), s);
	}

	public void setFloat(PE i, Float f) {
		setFloat(i.index(), f);
	}

	public void setInt(PE i, Integer f) {
		setInt(i.index(), f);
	}

	public void setString(PE i, String s) {
		setString(i.index(), s);
	}

	public void setBoolean(int i, Boolean s) {
		getBoolean(i).setItem(s);
	}

	public void setFloat(int i, Float f) {
		getFloat(i).setItem(f);
	}

	public void setInt(int i, Integer f) {
		getInt(i).setItem(f);
	}

	public void setString(int i, String s) {
		getString(i).setItem(s);
	}

	@Override public ItemManager<String> getListBoxId() {
		return id;
	}

	@Override public ItemManager<String> getListBoxName() {
		return id;
	}

	@SuppressWarnings("unchecked") public void delete() {
		delete((TT) this);
	}

	@Override public void delete(TT t) {
		// if (om != null)
		// om.deleteListeners.remove(this);
		for (DeleteListener<TT> dol : deleteListeners)
			dol.delete(t);
	}

	public void setObservedManager(TT m) {

		if (om != null)
			om.deleteListeners.remove(this);

		om = m;

		if (om != null) {
			om.deleteListeners.add(this);

			for (int i = 0; i < properties.size(); i++)
				properties.get(i).setObservedManager(om.properties.get(i));

			pIndices.setObservedList(om.pIndices);

			updateFields();

			id.setObservedManager(m.id);
		} else {
			for (int i = 0; i < properties.size(); i++)
				properties.get(i).setObservedManager(null);

			pIndices.clear();

			id.setObservedManager(null);
		}
	}

	public abstract ObjectManager<?, ?, ?> parent();

	// field.setObservedManager(m.field) for all fields.
	public abstract void updateFields();

	public boolean sameAs(TT um) {
		if (um == null)
			return false;
		return sameAs(um.id);
	}

	public boolean sameAs(ItemManager<String> id) {
		if (id == null)
			return false;
		return sameAs(id.getItem());
	}

	public boolean sameAs(String s) {
		return id.getItem().equals(s);
	}
}
